/*
 *------------------------------------------------------------------------------
 * @File      :    sc200ai_mipi.c
 * @Date      :    2021-3-30
 * @Author    :    lomboswer <lomboswer@lombotech.com>
 * @Brief     :    Source file for MDP(Media Development Platform).
 *
 * Copyright (C) 2020-2021, LomboTech Co.Ltd. All rights reserved.
 *------------------------------------------------------------------------------
 */
#include "ei_comm_camera.h"
#include "camera_usr.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */

#define SNS_ID 200
#define SNS_NAME  "sc200ai_mipi"
#define DEV_TYPE MCSI

static VISS_DEV gaVissDev[ISP_MAX_DEV_NUM] = {-1};
static SNS_STATE_S g_sastSns[VISS_MAX_DEV_NUM];
#define MAX_SHORT_EXP           (0x13e)

#define MAX_AGAIN (53 * 1024 + 998)
#define MAX_DGAIN (31 * 1024 + 768)
static float again_ratio = 3.4;

static const SNS_REG_S s_aRaw1080p2Lane[] = {
    {0x0103,0x01},
    {0x0100,0x00},
    {0x36e9,0x80},
    {0x36f9,0x80},
    {0x301f,0x03},
    {0x3243,0x01},
    {0x3248,0x02},
    {0x3249,0x09},
    {0x3253,0x08},
    {0x3271,0x0a},
    {0x3301,0x20},
    {0x3304,0x40},
    {0x3306,0x32},
    {0x330b,0x88},
    {0x330f,0x02},
    {0x331e,0x39},
    {0x3333,0x10},
    {0x3621,0xe8},
    {0x3622,0x16},
    {0x3637,0x1b},
    {0x363a,0x1f},
    {0x363b,0xc6},
    {0x363c,0x0e},
    {0x3670,0x0a},
    {0x3674,0x82},
    {0x3675,0x76},
    {0x3676,0x78},
    {0x367c,0x48},
    {0x367d,0x58},
    {0x3690,0x34},
    {0x3691,0x33},
    {0x3692,0x44},
    {0x369c,0x40},
    {0x369d,0x48},
    {0x3901,0x02},
    {0x3904,0x04},
    {0x3908,0x41},
    {0x391d,0x14},
    {0x391f,0x18},
    {0x3e01,0x8c},
    {0x3e02,0x20},
    {0x3e16,0x00},
    {0x3e17,0x80},
    {0x3f09,0x48},
    {0x5787,0x10},
    {0x5788,0x06},
    {0x578a,0x10},
    {0x578b,0x06},
    {0x5790,0x10},
    {0x5791,0x10},
    {0x5792,0x00},
    {0x5793,0x10},
    {0x5794,0x10},
    {0x5795,0x00},
    {0x5799,0x00},
    {0x57c7,0x10},
    {0x57c8,0x06},
    {0x57ca,0x10},
    {0x57cb,0x06},
    {0x57d1,0x10},
    {0x57d4,0x10},
    {0x57d9,0x00},
    {0x59e0,0x60},
    {0x59e1,0x08},
    {0x59e2,0x3f},
    {0x59e3,0x18},
    {0x59e4,0x18},
    {0x59e5,0x3f},
    {0x59e6,0x06},
    {0x59e7,0x02},
    {0x59e8,0x38},
    {0x59e9,0x10},
    {0x59ea,0x0c},
    {0x59eb,0x10},
    {0x59ec,0x04},
    {0x59ed,0x02},
    {0x59ee,0xa0},
    {0x59ef,0x08},
    {0x59f4,0x18},
    {0x59f5,0x10},
    {0x59f6,0x0c},
    {0x59f7,0x10},
    {0x59f8,0x06},
    {0x59f9,0x02},
    {0x59fa,0x18},
    {0x59fb,0x10},
    {0x59fc,0x0c},
    {0x59fd,0x10},
    {0x59fe,0x04},
    {0x59ff,0x02},
    {0x36e9,0x20},
    {0x36f9,0x27},
    /* close tream on in reg list*/
    /* {0x0100,0x01},*/
};

static const SNS_REG_S s_aRaw1080p2to12Lane[] = {
	{0x0103,0x01},
	{0x0100,0x00},
	{0x36e9,0x80},
	{0x36f9,0x80},
	{0x301f,0x02},
	{0x320e,0x08},
	{0x320f,0xca},
	{0x3220,0x53},
	{0x3243,0x01},
	{0x3248,0x02},
	{0x3249,0x09},
	{0x3250,0x3f},
	{0x3253,0x08},
	{0x3271,0x0a},
	{0x3301,0x06},
	{0x3302,0x0c},
	{0x3303,0x08},
	{0x3304,0x60},
	{0x3306,0x30},
	{0x3308,0x10},
	{0x3309,0x70},
	{0x330b,0x80},
	{0x330d,0x16},
	{0x330e,0x1c},
	{0x330f,0x02},
	{0x3310,0x02},
	{0x331c,0x04},
	{0x331e,0x51},
	{0x331f,0x61},
	{0x3320,0x07},
	{0x3333,0x10},
	{0x334c,0x08},
	{0x3356,0x09},
	{0x3364,0x17},
	{0x3390,0x08},
	{0x3391,0x18},
	{0x3392,0x38},
	{0x3393,0x06},
	{0x3394,0x06},
	{0x3395,0x06},
	{0x3396,0x08},
	{0x3397,0x18},
	{0x3398,0x38},
	{0x3399,0x06},
	{0x339a,0x0a},
	{0x339b,0x10},
	{0x339c,0x20},
	{0x33ac,0x08},
	{0x33ae,0x10},
	{0x33af,0x19},
	{0x3621,0xe8},
	{0x3622,0x16},
	{0x3630,0xa0},
	{0x3637,0x36},
	{0x363a,0x1f},
	{0x363b,0xc6},
	{0x363c,0x0e},
	{0x3670,0x0a},
	{0x3674,0x82},
	{0x3675,0x76},
	{0x3676,0x78},
	{0x367c,0x48},
	{0x367d,0x58},
	{0x3690,0x34},
	{0x3691,0x33},
	{0x3692,0x44},
	{0x369c,0x40},
	{0x369d,0x48},
	{0x36eb,0x0c},
	{0x36ec,0x0c},
	{0x36fd,0x14},
	{0x3901,0x02},
	{0x3904,0x04},
	{0x3908,0x41},
	{0x391f,0x10},
	{0x3e00,0x01},
	{0x3e01,0x06},
	{0x3e02,0x00},
	{0x3e04,0x10},
	{0x3e05,0x60},
	{0x3e06,0x00},
	{0x3e07,0x80},
	{0x3e08,0x03},
	{0x3e09,0x40},
	{0x3e10,0x00},
	{0x3e11,0x80},
	{0x3e12,0x03},
	{0x3e13,0x40},
	{0x3e16,0x00},
	{0x3e17,0x80},
	{0x3e23,MAX_SHORT_EXP >> 8},
	{0x3e24,MAX_SHORT_EXP & 0xff},
	{0x3f09,0x48},
	{0x4816,0xb1},
	{0x4819,0x09},
	{0x481b,0x05},
	{0x481d,0x14},
	{0x481f,0x04},
	{0x4821,0x0a},
	{0x4823,0x05},
	{0x4825,0x04},
	{0x4827,0x05},
	{0x4829,0x08},
	{0x5787,0x10},
	{0x5788,0x06},
	{0x578a,0x10},
	{0x578b,0x06},
	{0x5790,0x10},
	{0x5791,0x10},
	{0x5792,0x00},
	{0x5793,0x10},
	{0x5794,0x10},
	{0x5795,0x00},
	{0x5799,0x00},
	{0x57c7,0x10},
	{0x57c8,0x06},
	{0x57ca,0x10},
	{0x57cb,0x06},
	{0x57d1,0x10},
	{0x57d4,0x10},
	{0x57d9,0x00},
	{0x59e0,0x60},
	{0x59e1,0x08},
	{0x59e2,0x3f},
	{0x59e3,0x18},
	{0x59e4,0x18},
	{0x59e5,0x3f},
	{0x59e6,0x06},
	{0x59e7,0x02},
	{0x59e8,0x38},
	{0x59e9,0x10},
	{0x59ea,0x0c},
	{0x59eb,0x10},
	{0x59ec,0x04},
	{0x59ed,0x02},
	{0x59ee,0xa0},
	{0x59ef,0x08},
	{0x59f4,0x18},
	{0x59f5,0x10},
	{0x59f6,0x0c},
	{0x59f7,0x10},
	{0x59f8,0x06},
	{0x59f9,0x02},
	{0x59fa,0x18},
	{0x59fb,0x10},
	{0x59fc,0x0c},
	{0x59fd,0x10},
	{0x59fe,0x04},
	{0x59ff,0x02},
	{0x36e9,0x20},
	{0x36f9,0x24},
    /* close tream on in reg list*/
    /* {0x0100,0x01},*/
};
static const SNS_REG_S s_aRaw1080p60fps[] = {
    {0x0103,0x01},
    {0x0100,0x00},
    {0x36e9,0x80},
    {0x36f9,0x80},
    {0x301f,0x01},
    {0x3243,0x01},
    {0x3248,0x02},
    {0x3249,0x09},
    {0x3253,0x08},
    {0x3271,0x0a},
    {0x3301,0x06},
    {0x3302,0x0c},
    {0x3303,0x08},
    {0x3304,0x60},
    {0x3306,0x30},
    {0x3308,0x10},
    {0x3309,0x70},
    {0x330b,0x80},
    {0x330d,0x16},
    {0x330e,0x1c},
    {0x330f,0x02},
    {0x3310,0x02},
    {0x331c,0x04},
    {0x331e,0x51},
    {0x331f,0x61},
    {0x3320,0x07},
    {0x3333,0x10},
    {0x334c,0x08},
    {0x3356,0x09},
    {0x3364,0x17},
    {0x3390,0x08},
    {0x3391,0x18},
    {0x3392,0x38},
    {0x3393,0x06},
    {0x3394,0x06},
    {0x3395,0x06},
    {0x3396,0x08},
    {0x3397,0x18},
    {0x3398,0x38},
    {0x3399,0x06},
    {0x339a,0x0a},
    {0x339b,0x10},
    {0x339c,0x20},
    {0x33ac,0x08},
    {0x33ae,0x10},
    {0x33af,0x19},
    {0x3621,0xe8},
    {0x3622,0x16},
    {0x3630,0xa0},
    {0x3637,0x36},
    {0x363a,0x1f},
    {0x363b,0xc6},
    {0x363c,0x0e},
    {0x3670,0x0a},
    {0x3674,0x82},
    {0x3675,0x76},
    {0x3676,0x78},
    {0x367c,0x48},
    {0x367d,0x58},
    {0x3690,0x34},
    {0x3691,0x33},
    {0x3692,0x44},
    {0x369c,0x40},
    {0x369d,0x48},
    {0x36eb,0x0c},
    {0x36ec,0x0c},
    {0x36fd,0x14},
    {0x3901,0x02},
    {0x3904,0x04},
    {0x3908,0x41},
    {0x391f,0x10},
    {0x3e01,0x8c},
    {0x3e02,0x20},
    {0x3e16,0x00},
    {0x3e17,0x80},
    {0x3f09,0x48},
    {0x4819,0x09},
    {0x481b,0x05},
    {0x481d,0x14},
    {0x481f,0x04},
    {0x4821,0x0a},
    {0x4823,0x05},
    {0x4825,0x04},
    {0x4827,0x05},
    {0x4829,0x08},
    {0x5787,0x10},
    {0x5788,0x06},
    {0x578a,0x10},
    {0x578b,0x06},
    {0x5790,0x10},
    {0x5791,0x10},
    {0x5792,0x00},
    {0x5793,0x10},
    {0x5794,0x10},
    {0x5795,0x00},
    {0x5799,0x00},
    {0x57c7,0x10},
    {0x57c8,0x06},
    {0x57ca,0x10},
    {0x57cb,0x06},
    {0x57d1,0x10},
    {0x57d4,0x10},
    {0x57d9,0x00},
    {0x59e0,0x60},
    {0x59e1,0x08},
    {0x59e2,0x3f},
    {0x59e3,0x18},
    {0x59e4,0x18},
    {0x59e5,0x3f},
    {0x59e6,0x06},
    {0x59e7,0x02},
    {0x59e8,0x38},
    {0x59e9,0x10},
    {0x59ea,0x0c},
    {0x59eb,0x10},
    {0x59ec,0x04},
    {0x59ed,0x02},
    {0x59ee,0xa0},
    {0x59ef,0x08},
    {0x59f4,0x18},
    {0x59f5,0x10},
    {0x59f6,0x0c},
    {0x59f7,0x10},
    {0x59f8,0x06},
    {0x59f9,0x02},
    {0x59fa,0x18},
    {0x59fb,0x10},
    {0x59fc,0x0c},
    {0x59fd,0x10},
    {0x59fe,0x04},
    {0x59ff,0x02},
    {0x36e9,0x20},
    {0x36f9,0x24},
	{0x0100,0x01},
};

static CAMERA_POWER_ACT_S s_stPowerUpAct[] = {
    {SNS_RESET, SNS_DOWN},
    {SNS_DELAY, 10},
    {SNS_PWDN,  SNS_DOWN},
    {SNS_DELAY, 10},
    {SNS_RESET, SNS_UP},
    {SNS_DELAY, 10},
    {SNS_PWDN,  SNS_UP},
    {SNS_DELAY, 10},
};

static CAMERA_POWER_ACT_S s_sPowerDownAct[] = {
    {SNS_PWDN, SNS_DOWN},
    {SNS_DELAY, 10},
    {SNS_RESET, SNS_UP},
    {SNS_DELAY, 10},
};

/*vts:{0x320e,0x320f}
 *hts:{0x320c,0x320d}
 *
 */

static SNS_TYPE_ATTR_S s_astSnsAttr[] = {
    {
        .enSnsType                  = SC200AI_MIPI_1920_1080_25FPS_RAW10,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_10BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_BGGR,
        .stSize                     = {1920, 1080},
        .u32Mclock                  = 27000000,
        .enWorkMode                 = VISS_WORK_MODE_1Chn,

        .u32IspClk                  = 99000000,
        .u32IppuClk                 = 198000000,
        .u32Pclk                    = 71280000,
        .u32Vts                     = 1350,
        .u32Hts                     = 2112,

        .u32FrameRate               = 25,
        .astRegCfgs[0].pstRegs      = s_aRaw1080p2Lane,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw1080p2Lane),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 375*1000*1000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_2Lane,
    },
    {
        .enSnsType                  = SC200AI_MIPI_1920_1080_30FPS_RAW10,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_10BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_BGGR,
        .stSize                     = {1920, 1080},
        .u32Mclock                  = 27000000,
        .enWorkMode                 = VISS_WORK_MODE_1Chn,

        .u32IspClk                  = 99000000,
        .u32IppuClk                 = 198000000,
        .u32Pclk                    = 71280000,
        .u32Vts                     = 1125,
        .u32Hts                     = 2112,

        .u32FrameRate               = 30,
        .astRegCfgs[0].pstRegs      = s_aRaw1080p2Lane,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw1080p2Lane),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 375*1000*1000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_2Lane,
    },

    {
        .enSnsType                  = SC200AI_MIPI_1920_1080_60FPS_RAW10,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_10BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_BGGR,
        .stSize                     = {1920, 1080},
        .u32ModuleClk               = 198000000,
        .u32Mclock                  = 27000000,
        .enWorkMode                 = VISS_WORK_MODE_1Chn,

        .u32IspClk                  = 148500000,
        .u32IppuClk                 = 297000000,

        .u32Pclk                    = 2200 * 1125 * 60,
        .u32Vts                     = 1125,
        .u32Hts                     = 2200,

        .u32FrameRate               = 60,
        .astRegCfgs[0].pstRegs      = s_aRaw1080p60fps,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw1080p60fps),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 375*1000*1000 * 2,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_2Lane,
    },

    {
        .enSnsType                  = SC200AI_MIPI_1920_1080_25FPS_2TO1_RAW10,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_10BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_BGGR,
        .stSize                     = {1920, 1080},
        .u32Mclock                  = 27000000,
        .enWorkMode                 = VISS_WORK_MODE_2Chn,
        .enWdrMode                  = VISS_WDR_MODE_VC,

        .u32IspClk                  = 99000000,
        .u32IppuClk                 = 198000000,
        .u32Pclk                    = 142560000,
        .u32Vts                     = 2700,
        .u32Hts                     = 2112,
        .enIspWdrMode               = WDR_MODE_2TO1_FRAME,

        .u32FrameRate               = 25,
        .astRegCfgs[0].pstRegs      = s_aRaw1080p2to12Lane,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw1080p2to12Lane),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 742500000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_2Lane,
    },
    {
        .enSnsType                  = SC200AI_MIPI_1920_1080_30FPS_2TO1_RAW10,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_10BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_BGGR,
        .stSize                     = {1920, 1080},
        .u32Mclock                  = 27000000,
        .enWorkMode                 = VISS_WORK_MODE_2Chn,
        .enWdrMode                  = VISS_WDR_MODE_VC,

        .u32IspClk                  = 99000000,
        .u32IppuClk                 = 198000000,
        .u32Pclk                    = 142560000,
        .u32Vts                     = 2250,
        .u32Hts                     = 2112,
        .enIspWdrMode               = WDR_MODE_2TO1_FRAME,

        .u32FrameRate               = 30,
        .astRegCfgs[0].pstRegs      = s_aRaw1080p2to12Lane,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw1080p2to12Lane),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 742500000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_2Lane,
    },
};

static int CAMERA_SetI2cInfo(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    if (pstSnsState->stI2cInfo.fd > 0) {
        return EI_SUCCESS;
    }

    pstSnsState->stI2cInfo.u8RegBits = 16;
    pstSnsState->stI2cInfo.u8ValBits = 8;
    pstSnsState->stI2cInfo.u16I2cBusNum = 4;
    pstSnsState->stI2cInfo.u16I2cDevAddr = 0x30;
    pstSnsState->pcName = SNS_NAME;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_Detect(VISS_DEV VissDev)
{
    EI_U8 u8Tmp[2];
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U16 u16Id;
    SNS_STATE_S *pstSnsState = EI_NULL;
    I2C_INFO_S *pstI2cInfo = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    pstI2cInfo = &pstSnsState->stI2cInfo;

    CAMERA_CHECK_POINTER(pstI2cInfo->pfnReadReg);
    s32Ret = pstI2cInfo->pfnReadReg(pstSnsState, 0x3107, &u8Tmp[0]);
    if (s32Ret != 0) {
        PRT_VISS_ERR("tmp[0]=%x\n", u8Tmp[0]);
        return s32Ret;
    }
    s32Ret = pstI2cInfo->pfnReadReg(pstSnsState, 0x3108, &u8Tmp[1]);
    if (s32Ret != 0) {
        PRT_VISS_ERR("tmp[0]=%x,tmp[1]=%x\n", u8Tmp[0], u8Tmp[1]);
        return s32Ret;
    }
    u16Id = (u8Tmp[0] << 8) | u8Tmp[1];
    PRT_VISS_INFO("%s id: 0x%04x\n", SNS_NAME, u16Id);

    if (u16Id != 0xcb1c) {
        PRT_VISS_ERR("%s ID wrong! (0x%04x != 0xcb1c)\n", SNS_NAME, u16Id);
        return EI_FAILURE;
    }

    return EI_SUCCESS;
}


static EI_S32 CAMERA_Stream(VISS_DEV dev, EI_BOOL bOn)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);
    PRT_VISS_ERR("%s CAMERA_Stream*******%d\n", SNS_NAME, bOn);

    if (bOn) {
        s32Ret = pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x0100, 0x01);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("CAMERA_Stream*******%d\n", bOn);
        }
    } else {
        s32Ret = pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x0100, 0x00);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("CAMERA_Stream*******%d\n", bOn);
        }
    }
    return s32Ret;

}

/* The following functions can be modified as needed */

static int CAMERA_I2cInit(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    int ret = EI_SUCCESS;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    ret = CAMERA_SetI2cInfo(dev);
    CAMERA_CHECK_SUCCESS(ret);

    ret = CAMERA_I2C_Reg_Ops(&pstSnsState->stI2cInfo);
    CAMERA_CHECK_SUCCESS(ret);

    return EI_SUCCESS;
}

static int CAMERA_I2cExit(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_PowerUp(VISS_DEV VissDev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    CAMERA_SensorPowerUp(VissDev, pstSnsState);

    return 0;
}

static EI_S32 CAMERA_PowerDown(VISS_DEV VissDev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    CAMERA_SensorPowerDown(VissDev, pstSnsState);

    return 0;
}

static EI_S32 CAMERA_MirrorFlip(VISS_DEV VissDev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    I2C_INFO_S *pstI2cInfo = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U32 u32Tmp = 0;

    SNS_GET_CTX(VissDev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstI2cInfo = &pstSnsState->stI2cInfo;

    PRT_VISS_INFO("%s set mirror[%d] flip[%d] \n", SNS_NAME,
        pstSnsState->u32SnsMirror, pstSnsState->u32SnsFlip);

    if (!pstSnsState->u32SnsMirror && !pstSnsState->u32SnsFlip) {
        s32Ret = pstI2cInfo->pfnWriteReg(pstSnsState, 0x3221, (u32Tmp & 0x99 ) | 0x00);
        if (s32Ret != 0) {
            PRT_VISS_ERR("%s pfnWriteReg error\n", SNS_NAME);
            return s32Ret;
        }
        return s32Ret;
    }

    /* sensor flip & mirror */
    pstI2cInfo->pfnReadReg(pstSnsState, 0x3221, &u32Tmp);
    if (s32Ret != 0) {
        PRT_VISS_ERR("%s pfnReadReg error\n", SNS_NAME);
        return s32Ret;
    }

    if (pstSnsState->u32SnsMirror) {
        s32Ret = pstI2cInfo->pfnWriteReg(pstSnsState, 0x3221, (u32Tmp & 0xf9 ) | 0x06);
    } else {
        s32Ret = pstI2cInfo->pfnWriteReg(pstSnsState, 0x3221, (u32Tmp & 0xf9 ));
    }
    if (s32Ret != 0) {
        PRT_VISS_ERR("%s pfnWriteReg error\n", SNS_NAME);
        return s32Ret;
    }

    pstI2cInfo->pfnReadReg(pstSnsState, 0x3221, &u32Tmp);
    if (s32Ret != 0) {
        PRT_VISS_ERR("%s pfnReadReg error\n", SNS_NAME);
        return s32Ret;
    }

    if (pstSnsState->u32SnsFlip) {
        s32Ret = pstI2cInfo->pfnWriteReg(pstSnsState, 0x3221, (u32Tmp & 0x9f ) | 0x60);
    } else {
        s32Ret = pstI2cInfo->pfnWriteReg(pstSnsState, 0x3221, (u32Tmp & 0x9f ));
    }
    if (s32Ret != 0) {
        PRT_VISS_ERR("%s pfnWriteReg error\n", SNS_NAME);
        return s32Ret;
    }

    return s32Ret;
}

static EI_S32 CAMERA_SetGain(ISP_DEV dev, EI_FLOAT fGain);
static EI_S32 CAMERA_SetExpTime(ISP_DEV dev, EI_FLOAT *afIntTime);

static EI_S32 CAMERA_Init(VISS_DEV dev)
{
    EI_U32 j;
    const SNS_TYPE_ATTR_S *pstSnsType;
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret;
    I2C_INFO_S *pstI2cInfo = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstI2cInfo = &pstSnsState->stI2cInfo;

    pstSnsType = pstSnsState->pstSnsAttr;
    for (j = 0; j < MAX_COF; j++) {
        s32Ret = pstSnsState->stI2cInfo.pfnwriteRegList(pstSnsState,
                pstSnsType->astRegCfgs[j].pstRegs, pstSnsType->astRegCfgs[j].u32RegsCnt);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("%s writeRegList err\n", SNS_NAME);
            return s32Ret;
        }
    }

    if(pstSnsType->enSnsType == SC200AI_MIPI_1920_1080_25FPS_RAW10) {
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x320e, 0x05);
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x320f, 0x46);
        if (s32Ret != 0) {
            PRT_VISS_ERR("CAMERA_Init error\n");
            return s32Ret;
        }
    }

    if(pstSnsType->enSnsType == SC200AI_MIPI_1920_1080_25FPS_2TO1_RAW10) {
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x320e, 0x0a);
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x320f, 0x8c);
        if (s32Ret != 0) {
            PRT_VISS_ERR("CAMERA_Init error\n");
            return s32Ret;
        }
    }

    if ((pstSnsState->afIntTime[0] > 0.000001) && (pstSnsState->fGain >= 1.0)) {
        CAMERA_SetExpTime(pstSnsState->IspDev, pstSnsState->afIntTime);
        CAMERA_SetGain(pstSnsState->IspDev, pstSnsState->fGain);
    }

    CAMERA_MirrorFlip(dev);

    PRT_VISS_INFO("%s writeRegList success\n", SNS_NAME);

    return s32Ret;
}

static void CAMERA_Exit(VISS_DEV dev)
{
    CAMERA_I2cExit(dev);

    return;
}

static EI_S32 CAMERA_SetImageMode(VISS_DEV dev, SNS_TYPE_E enSnsType)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstSnsState->enSnsType = enSnsType;
    pstSnsState->bSyncInit = EI_FALSE;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_EnumSnstype(VISS_DEV VissDev, EI_U32 u32Index, SNS_TYPE_E *peSnstype)
{
    const SNS_TYPE_ATTR_S *pstSnsType;

    if (u32Index >= ARRAY_SIZE(s_astSnsAttr))
        return EN_ERR_NO_FOUND;

    pstSnsType = &s_astSnsAttr[u32Index];

    *peSnstype = pstSnsType->enSnsType;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_SetFrameRate(VISS_DEV VissDev, EI_FLOAT f32Fps)
{
    I2C_INFO_S *pstI2cInfo = EI_NULL;
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U32 u32Pclk, u32Hts, u32Vts;

    SNS_GET_CTX(VissDev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstI2cInfo = &pstSnsState->stI2cInfo;
    u32Pclk = pstSnsState->pstSnsAttr->u32Pclk;
    u32Hts = pstSnsState->pstSnsAttr->u32Hts;

    if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_NONE) {
        if (pstSnsState->pstSnsAttr->u32FrameRate < f32Fps || 1 > f32Fps) {
            cprintf("1 <= set fps <= %d, set fps: %f\n", pstSnsState->pstSnsAttr->u32FrameRate, f32Fps);
            f32Fps = pstSnsState->pstSnsAttr->u32FrameRate;
        }

        u32Vts = u32Pclk / u32Hts / f32Fps;

        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x320e, u32Vts >> 8);
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x320f, u32Vts);

        if (s32Ret != 0) {
            cprintf("CAMERA_Init error\n");
            return s32Ret;
        }
    } else if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_2TO1_FRAME) {
        if (pstSnsState->pstSnsAttr->u32FrameRate < f32Fps || 1 > f32Fps) {
            cprintf("1 <= set fps <= %d, set fps: %f\n", pstSnsState->pstSnsAttr->u32FrameRate, f32Fps);
            f32Fps = pstSnsState->pstSnsAttr->u32FrameRate;
        }

        u32Vts = u32Pclk / u32Hts / f32Fps;

        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x320e, u32Vts >> 8);
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x320f, u32Vts);

        if (s32Ret != 0) {
            cprintf("CAMERA_Init error\n");
            return s32Ret;
        }
    } else {
        return EN_ERR_NOT_SUPPORT;
    }
    pstSnsState->pstSnsAttr->u32Vts = u32Vts;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_InitSensorExpFunction(SENSOR_EXP_FUNC_S *pstSensorExpFunc)
{
    CAMERA_CHECK_POINTER(pstSensorExpFunc);

    memset(pstSensorExpFunc, 0, sizeof(SENSOR_EXP_FUNC_S));

    pstSensorExpFunc->pfnSensorPowerUp  = CAMERA_PowerUp;
    pstSensorExpFunc->pfnSensorPowerDown = CAMERA_PowerDown;
    pstSensorExpFunc->pfnSensorDetect   = CAMERA_Detect;
    pstSensorExpFunc->pfnSensorInit     = CAMERA_Init;
    pstSensorExpFunc->pfnSensorStream   = CAMERA_Stream;
    pstSensorExpFunc->pfnSensorExit     = CAMERA_Exit;
    pstSensorExpFunc->pfnSensorSetImageMode   = CAMERA_SetImageMode;
    pstSensorExpFunc->pfnSensorEnumSnstype   = CAMERA_EnumSnstype;
    pstSensorExpFunc->pfnSensorSetFrameRate   = CAMERA_SetFrameRate;
    pstSensorExpFunc->pfnSensorSetMirrorFlip = CAMERA_MirrorFlip;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_GetAeDefault(ISP_DEV dev, AE_SENSOR_DEFAULT_S *pstAeSnsDft)
{
    CAMERA_CHECK_POINTER(pstAeSnsDft);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_SetFps(ISP_DEV dev, EI_FLOAT f32Fps, AE_SENSOR_DEFAULT_S *pstAeSnsDft)
{
    VISS_DEV Dev;

    SNS_GET_ISP_TO_VISS(dev, Dev);

    CAMERA_CHECK_POINTER(pstAeSnsDft);

    return CAMERA_SetFrameRate(Dev, f32Fps);
}

static EI_U32 again_index[256] = {
    1024, 1040, 1056, 1072, 1088, 1104, 1120, 1136, 1152, 1168, 1184, 1200, 1216, 1232, 1248, 1264,
    1280, 1296, 1312, 1328, 1344, 1360, 1376, 1392, 1408, 1424, 1440, 1456, 1472, 1488, 1504, 1520,
    1536, 1552, 1568, 1584, 1600, 1616, 1632, 1648, 1664, 1680, 1696, 1712, 1728, 1744, 1760, 1776,
    1792, 1808, 1824, 1840, 1856, 1872, 1888, 1904, 1920, 1936, 1952, 1968, 1984, 2000, 2016, 2032,
    2048, 2080, 2112, 2144, 2176, 2208, 2240, 2272, 2304, 2336, 2368, 2400, 2432, 2464, 2496, 2528,
    2560, 2592, 2624, 2656, 2688, 2720, 2752, 2784, 2816, 2848, 2880, 2912, 2944, 2976, 3008, 3040,
    3072, 3104, 3136, 3168, 3200, 3232, 3264, 3296, 3328, 3360, 3392, 3424, 3456, 3488, 3520, 3552,
    3584, 3616, 3648, 3680, 3712, 3744, 3776, 3808, 3840, 3872, 3904, 3936, 3968, 4000, 4032, 4064,
    4096, 4160, 4224, 4288, 4352, 4416, 4480, 4544, 4608, 4672, 4736, 4800, 4864, 4928, 4992, 5056,
    5120, 5184, 5248, 5312, 5376, 5440, 5504, 5568, 5632, 5696, 5760, 5824, 5888, 5952, 6016, 6080,
    6144, 6208, 6272, 6336, 6400, 6464, 6528, 6592, 6656, 6720, 6784, 6848, 6912, 6976, 7040, 7104,
    7168, 7232, 7296, 7360, 7424, 7488, 7552, 7616, 7680, 7744, 7808, 7872, 7936, 8000, 8064, 8128,
    8192, 8320, 8448, 8576, 8704, 8832, 8960, 9088, 9216, 9344, 9472, 9600, 9728, 9856, 9984, 10112,
    10240, 10368, 10496, 10624, 10752, 10880, 11008, 11136, 11264, 11392, 11520, 11648, 11776, 11904, 12032, 12160,
    12288, 12416, 12544, 12672, 12800, 12928, 13056, 13184, 13312, 13440, 13568, 13696, 13824, 13952, 14080, 14208,
    14336, 14464, 14592, 14720, 14848, 14976, 15104, 15232, 15360, 15488, 15616, 15744, 15872, 16000, 16128, 16256
};

static EI_U32 dgain_index[256] = {
    1024, 1040, 1056, 1072, 1088, 1104, 1120, 1136, 1152, 1168, 1184, 1200, 1216, 1232, 1248, 1264,
    1280, 1296, 1312, 1328, 1344, 1360, 1376, 1392, 1408, 1424, 1440, 1456, 1472, 1488, 1504, 1520,
    1536, 1552, 1568, 1584, 1600, 1616, 1632, 1648, 1664, 1680, 1696, 1712, 1728, 1744, 1760, 1776,
    1792, 1808, 1824, 1840, 1856, 1872, 1888, 1904, 1920, 1936, 1952, 1968, 1984, 2000, 2016, 2032,
    2048, 2080, 2112, 2144, 2176, 2208, 2240, 2272, 2304, 2336, 2368, 2400, 2432, 2464, 2496, 2528,
    2560, 2592, 2624, 2656, 2688, 2720, 2752, 2784, 2816, 2848, 2880, 2912, 2944, 2976, 3008, 3040,
    3072, 3104, 3136, 3168, 3200, 3232, 3264, 3296, 3328, 3360, 3392, 3424, 3456, 3488, 3520, 3552,
    3584, 3616, 3648, 3680, 3712, 3744, 3776, 3808, 3840, 3872, 3904, 3936, 3968, 4000, 4032, 4064,
    4096, 4160, 4224, 4288, 4352, 4416, 4480, 4544, 4608, 4672, 4736, 4800, 4864, 4928, 4992, 5056,
    5120, 5184, 5248, 5312, 5376, 5440, 5504, 5568, 5632, 5696, 5760, 5824, 5888, 5952, 6016, 6080,
    6144, 6208, 6272, 6336, 6400, 6464, 6528, 6592, 6656, 6720, 6784, 6848, 6912, 6976, 7040, 7104,
    7168, 7232, 7296, 7360, 7424, 7488, 7552, 7616, 7680, 7744, 7808, 7872, 7936, 8000, 8064, 8128,
    8192, 8320, 8448, 8576, 8704, 8832, 8960, 9088, 9216, 9344, 9472, 9600, 9728, 9856, 9984, 10112,
    10240, 10368, 10496, 10624, 10752, 10880, 11008, 11136, 11264, 11392, 11520, 11648, 11776, 11904, 12032, 12160,
    12288, 12416, 12544, 12672, 12800, 12928, 13056, 13184, 13312, 13440, 13568, 13696, 13824, 13952, 14080, 14208,
    14336, 14464, 14592, 14720, 14848, 14976, 15104, 15232, 15360, 15488, 15616, 15744, 15872, 16000, 16128, 16256
};

static EI_U32 again_table[256] = {
    0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347, 0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F,
    0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, 0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F,
    0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, 0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F,
    0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377, 0x0378, 0x0379, 0x037A, 0x037B, 0x037C, 0x037D, 0x037E, 0x037F,
    0x0740, 0x0741, 0x0742, 0x0743, 0x0744, 0x0745, 0x0746, 0x0747, 0x0748, 0x0749, 0x074A, 0x074B, 0x074C, 0x074D, 0x074E, 0x074F,
    0x0750, 0x0751, 0x0752, 0x0753, 0x0754, 0x0755, 0x0756, 0x0757, 0x0758, 0x0759, 0x075A, 0x075B, 0x075C, 0x075D, 0x075E, 0x075F,
    0x0760, 0x0761, 0x0762, 0x0763, 0x0764, 0x0765, 0x0766, 0x0767, 0x0768, 0x0769, 0x076A, 0x076B, 0x076C, 0x076D, 0x076E, 0x076F,
    0x0770, 0x0771, 0x0772, 0x0773, 0x0774, 0x0775, 0x0776, 0x0777, 0x0778, 0x0779, 0x077A, 0x077B, 0x077C, 0x077D, 0x077E, 0x077F,
    0x0F40, 0x0F41, 0x0F42, 0x0F43, 0x0F44, 0x0F45, 0x0F46, 0x0F47, 0x0F48, 0x0F49, 0x0F4A, 0x0F4B, 0x0F4C, 0x0F4D, 0x0F4E, 0x0F4F,
    0x0F50, 0x0F51, 0x0F52, 0x0F53, 0x0F54, 0x0F55, 0x0F56, 0x0F57, 0x0F58, 0x0F59, 0x0F5A, 0x0F5B, 0x0F5C, 0x0F5D, 0x0F5E, 0x0F5F,
    0x0F60, 0x0F61, 0x0F62, 0x0F63, 0x0F64, 0x0F65, 0x0F66, 0x0F67, 0x0F68, 0x0F69, 0x0F6A, 0x0F6B, 0x0F6C, 0x0F6D, 0x0F6E, 0x0F6F,
    0x0F70, 0x0F71, 0x0F72, 0x0F73, 0x0F74, 0x0F75, 0x0F76, 0x0F77, 0x0F78, 0x0F79, 0x0F7A, 0x0F7B, 0x0F7C, 0x0F7D, 0x0F7E, 0x0F7F,
    0x1F40, 0x1F41, 0x1F42, 0x1F43, 0x1F44, 0x1F45, 0x1F46, 0x1F47, 0x1F48, 0x1F49, 0x1F4A, 0x1F4B, 0x1F4C, 0x1F4D, 0x1F4E, 0x1F4F,
    0x1F50, 0x1F51, 0x1F52, 0x1F53, 0x1F54, 0x1F55, 0x1F56, 0x1F57, 0x1F58, 0x1F59, 0x1F5A, 0x1F5B, 0x1F5C, 0x1F5D, 0x1F5E, 0x1F5F,
    0x1F60, 0x1F61, 0x1F62, 0x1F63, 0x1F64, 0x1F65, 0x1F66, 0x1F67, 0x1F68, 0x1F69, 0x1F6A, 0x1F6B, 0x1F6C, 0x1F6D, 0x1F6E, 0x1F6F,
    0x1F70, 0x1F71, 0x1F72, 0x1F73, 0x1F74, 0x1F75, 0x1F76, 0x1F77, 0x1F78, 0x1F79, 0x1F7A, 0x1F7B, 0x1F7C, 0x1F7D, 0x1F7E, 0x1F7F
};

static EI_U32 dgain_table[256] = {
    0x0080, 0x0082, 0x0084, 0x0086, 0x0088, 0x008A, 0x008C, 0x008E, 0x0090, 0x0092, 0x0094, 0x0096, 0x0098, 0x009A, 0x009C, 0x009E,
    0x00A0, 0x00A2, 0x00A4, 0x00A6, 0x00A8, 0x00AA, 0x00AC, 0x00AE, 0x00B0, 0x00B2, 0x00B4, 0x00B6, 0x00B8, 0x00BA, 0x00BC, 0x00BE,
    0x00C0, 0x00C2, 0x00C4, 0x00C6, 0x00C8, 0x00CA, 0x00CC, 0x00CE, 0x00D0, 0x00D2, 0x00D4, 0x00D6, 0x00D8, 0x00DA, 0x00DC, 0x00DE,
    0x00E0, 0x00E2, 0x00E4, 0x00E6, 0x00E8, 0x00EA, 0x00EC, 0x00EE, 0x00F0, 0x00F2, 0x00F4, 0x00F6, 0x00F8, 0x00FA, 0x00FC, 0x00FE,
    0x0180, 0x0182, 0x0184, 0x0186, 0x0188, 0x018A, 0x018C, 0x018E, 0x0190, 0x0192, 0x0194, 0x0196, 0x0198, 0x019A, 0x019C, 0x019E,
    0x01A0, 0x01A2, 0x01A4, 0x01A6, 0x01A8, 0x01AA, 0x01AC, 0x01AE, 0x01B0, 0x01B2, 0x01B4, 0x01B6, 0x01B8, 0x01BA, 0x01BC, 0x01BE,
    0x01C0, 0x01C2, 0x01C4, 0x01C6, 0x01C8, 0x01CA, 0x01CC, 0x01CE, 0x01D0, 0x01D2, 0x01D4, 0x01D6, 0x01D8, 0x01DA, 0x01DC, 0x01DE,
    0x01E0, 0x01E2, 0x01E4, 0x01E6, 0x01E8, 0x01EA, 0x01EC, 0x01EE, 0x01F0, 0x01F2, 0x01F4, 0x01F6, 0x01F8, 0x01FA, 0x01FC, 0x01FE,
    0x0380, 0x0382, 0x0384, 0x0386, 0x0388, 0x038A, 0x038C, 0x038E, 0x0390, 0x0392, 0x0394, 0x0396, 0x0398, 0x039A, 0x039C, 0x039E,
    0x03A0, 0x03A2, 0x03A4, 0x03A6, 0x03A8, 0x03AA, 0x03AC, 0x03AE, 0x03B0, 0x03B2, 0x03B4, 0x03B6, 0x03B8, 0x03BA, 0x03BC, 0x03BE,
    0x03C0, 0x03C2, 0x03C4, 0x03C6, 0x03C8, 0x03CA, 0x03CC, 0x03CE, 0x03D0, 0x03D2, 0x03D4, 0x03D6, 0x03D8, 0x03DA, 0x03DC, 0x03DE,
    0x03E0, 0x03E2, 0x03E4, 0x03E6, 0x03E8, 0x03EA, 0x03EC, 0x03EE, 0x03F0, 0x03F2, 0x03F4, 0x03F6, 0x03F8, 0x03FA, 0x03FC, 0x03FE,
    0x0780, 0x0782, 0x0784, 0x0786, 0x0788, 0x078A, 0x078C, 0x078E, 0x0790, 0x0792, 0x0794, 0x0796, 0x0798, 0x079A, 0x079C, 0x079E,
    0x07A0, 0x07A2, 0x07A4, 0x07A6, 0x07A8, 0x07AA, 0x07AC, 0x07AE, 0x07B0, 0x07B2, 0x07B4, 0x07B6, 0x07B8, 0x07BA, 0x07BC, 0x07BE,
    0x07C0, 0x07C2, 0x07C4, 0x07C6, 0x07C8, 0x07CA, 0x07CC, 0x07CE, 0x07D0, 0x07D2, 0x07D4, 0x07D6, 0x07D8, 0x07DA, 0x07DC, 0x07DE,
    0x07E0, 0x07E2, 0x07E4, 0x07E6, 0x07E8, 0x07EA, 0x07EC, 0x07EE, 0x07F0, 0x07F2, 0x07F4, 0x07F6, 0x07F8, 0x07FA, 0x07FC, 0x07FE
};

static EI_U32 CAMERA_ConvertAgain2cfg(EI_U32 val)
{
    int finegain;
    EI_U32 gain;
    int i;
    gain = 0;
    finegain = val;

    if (finegain >= (int)(again_index[255] * again_ratio)) {
        finegain = (int)(again_index[255] * again_ratio);
        if (again_ratio > 1) {
            gain = again_table[255] | 0x2000;
        }
        else {
            gain = again_table[255];
        }
        return gain;
    }

    if (finegain >= (1024 * again_ratio)) {
        finegain /= again_ratio;

        for (i = 1; i < 256; i++) {
            if (finegain < again_index[i]) {
                gain = again_table[i - 1] | 0x2000;
                break;
            }
        }
    }
    else {
        for (i = 1; i < 256; i++) {
            if (finegain < again_index[i]) {
                gain = again_table[i - 1];
                break;
            }
        }
    }

    return gain;
}

static EI_U32 CAMERA_ConvertDgain2cfg(EI_U32 val)
{
    int finegain;
    EI_U32 gain;
    int i;
    gain = 0;
    finegain = val;


    if (finegain >= dgain_index[255]) {
        gain = dgain_table[255];
        return gain;
    }

    for (i = 1; i < 256; i++) {
        if (finegain < dgain_index[i]) {
            gain = dgain_table[i - 1];
            break;
        }
    }

    return gain;
}

static void CAMERA_CalcGain(EI_U32 gain, EI_U32 *_again, EI_U32 *_dgain)
{
    EI_U32 dgain, again;

    if (gain < 1024)
        gain = 1024;
    if (gain > 1500 * 1024)
        gain = 1500 * 1024;

    dgain = gain * 1024 / MAX_AGAIN;
    if (dgain < 1024)
        dgain = 1024;
    if (dgain > MAX_DGAIN)
        dgain = MAX_DGAIN;

    again = gain * 1024 / dgain;

    if (again < 1024)
        again = 1024;
    if (again > MAX_AGAIN)
        again = MAX_AGAIN;

    *_again = CAMERA_ConvertAgain2cfg(again);
    *_dgain = CAMERA_ConvertDgain2cfg(dgain);
}

static EI_S32 CAMERA_SetExpTime(ISP_DEV dev, EI_FLOAT *afIntTime)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U32 u32Pclk, u32Hts, u32Vts;
    EI_U32 shutter_time;
    VISS_DEV Dev;
    EI_U32 lexp, mexp, vmax;

    SNS_GET_ISP_TO_VISS(dev, Dev);

    SNS_GET_CTX(Dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);
    CAMERA_CHECK_POINTER(afIntTime);
    pstSnsState->afIntTime[0] = afIntTime[0];
    pstSnsState->afIntTime[1] = afIntTime[1];
    pstSnsState->afIntTime[2] = afIntTime[2];
    pstSnsState->afIntTime[3] = afIntTime[3];
    pstSnsState->IspDev = dev;
    CAMERA_CHECK_POWERON(pstSnsState);

    u32Pclk = pstSnsState->pstSnsAttr->u32Pclk;
    u32Hts = pstSnsState->pstSnsAttr->u32Hts;
    u32Vts = pstSnsState->pstSnsAttr->u32Vts;

    if ((u32Pclk == 0) || (u32Hts == 0) || (u32Vts == 0)) {
        PRT_VISS_ERR("error! u32Pclk %d, u32Hts %d, u32Vts %d\n", u32Pclk, u32Hts, u32Vts);
        return EI_FAILURE;
    }

    /* afIntTime[0] long/medium/short/vshort exptime (s) */
    shutter_time = afIntTime[0] * u32Pclk / u32Hts * 2;

    if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_NONE) {
        if (shutter_time > 2 * u32Vts - 8 )
            vmax = (shutter_time + 8) / 2;
        else
            vmax = u32Vts;

        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x320e, vmax >> 8);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x320f, vmax);

        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e00, (shutter_time >> 12) & 0x0f);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e01, (shutter_time >> 4) & 0xff);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e02, (shutter_time << 4) & 0xf0);
    } else if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_2TO1_FRAME) {

        if (afIntTime[1] < 1)
            afIntTime[1] = 1;

        if (shutter_time > (2 * u32Vts - 2 * MAX_SHORT_EXP - 10))
            lexp = (2 * u32Vts - 2 * MAX_SHORT_EXP - 10);
        else
            lexp = shutter_time;

        mexp = lexp / afIntTime[1];

        if (mexp < 1)
            mexp = 1;

        if (mexp > (2 * MAX_SHORT_EXP - 10))
            mexp = (2 * MAX_SHORT_EXP - 10);

        lexp = mexp * afIntTime[1];
        //printf("lexp %d, mexp %d\n", lexp, mexp);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e00, (lexp >> 12) & 0x0f);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e01, (lexp >> 4) & 0xff);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e02, (lexp << 4) & 0xf0);

        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e22, (mexp >> 12) & 0x0f);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e04, (mexp >> 4) & 0xff);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e05, (mexp << 4) & 0xf0);

        shutter_time = lexp;
    } else {
        PRT_VISS_ERR("no support\n");
    }

    afIntTime[0] = (EI_FLOAT)(shutter_time / 2) * u32Hts / u32Pclk;
    if (afIntTime[0] < 0.00001) {
        PRT_VISS_WARN("Warning! afIntTime[0] < 0.00001, now force 0.00001 \n");
        afIntTime[0] = 0.00001;
    }

    return EI_SUCCESS;
}

static EI_S32 CAMERA_SetGain(ISP_DEV dev, EI_FLOAT fGain)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U32 u32Gain;
    VISS_DEV Dev;
    EI_U32 again, dgain;

    SNS_GET_ISP_TO_VISS(dev, Dev);

    SNS_GET_CTX(Dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);
    pstSnsState->fGain = fGain;
    CAMERA_CHECK_POWERON(pstSnsState);

    if (fGain < 1)
        fGain = 1;

    if (fGain > 30) {
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x5799, 0x07);
    }
    else if (fGain > 20) {
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x5799, 0x00);
    }

    u32Gain = fGain * 256 * 4;

    CAMERA_CalcGain(u32Gain, &again, &dgain);

    s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e08, (again >> 8) & 0xff);
    s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e09, again & 0xff);
    s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e06, (dgain >> 8) & 0xff);
    s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e07, dgain & 0xff);

    if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_2TO1_FRAME) {
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e12, (again >> 8) & 0xff);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e13, again & 0xff);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e10, (dgain >> 8) & 0xff);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e11, dgain & 0xff);
    }

    return EI_SUCCESS;
}

static EI_S32 CAMERA_InitAeExpFunction(AE_SENSOR_EXP_FUNC_S *pstExpFuncs)
{
    CAMERA_CHECK_POINTER(pstExpFuncs);

    memset(pstExpFuncs, 0, sizeof(AE_SENSOR_EXP_FUNC_S));

    pstExpFuncs->pfnGetAeDefault    = CAMERA_GetAeDefault;
    pstExpFuncs->pfnSetFps          = CAMERA_SetFps;
    pstExpFuncs->pfnSetExpTime      = CAMERA_SetExpTime;
    pstExpFuncs->pfnSetGain         = CAMERA_SetGain;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_GetAwbDefault(ISP_DEV dev, AWB_SENSOR_DEFAULT_S *pstAwbSnsDft)
{
    CAMERA_CHECK_POINTER(pstAwbSnsDft);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_InitAwbExpFunction(AWB_SENSOR_EXP_FUNC_S *pstExpFuncs)
{
    CAMERA_CHECK_POINTER(pstExpFuncs);

    memset(pstExpFuncs, 0, sizeof(AWB_SENSOR_EXP_FUNC_S));
    pstExpFuncs->pfnGetAwbDefault = CAMERA_GetAwbDefault;

    return EI_SUCCESS;
}

/****************************************************************************
 * callback structure                                                       *
 ****************************************************************************/

static EI_S32 CAMERA_CtxInit(VISS_DEV dev)
{
    SNS_STATE_S *pastSnsStateCtx = EI_NULL;

    SNS_GET_CTX(dev, pastSnsStateCtx);

    CAMERA_CHECK_POINTER(pastSnsStateCtx);

    memset(pastSnsStateCtx, 0, sizeof(SNS_STATE_S));

    pastSnsStateCtx->pstPowerUpAct      = s_stPowerUpAct;
    pastSnsStateCtx->pstPowerDownAct    = s_sPowerDownAct;
    pastSnsStateCtx->u8PwrUpActs        = ARRAY_SIZE(s_stPowerUpAct);
    pastSnsStateCtx->u8PwrDnActs        = ARRAY_SIZE(s_sPowerDownAct);

    return EI_SUCCESS;
}

static EI_VOID CAMERA_CtxExit(VISS_DEV dev)
{
    return ;
}

static EI_S32 CAMERA_RegisterVissCallback(VISS_DEV dev, SNS_TYPE_E enType)
{
    EI_S32 s32Ret;
    SENSOR_S stSns = {0};
    EI_U32 i;
    SNS_STATE_S *pstSnsState = EI_NULL;

    s32Ret = CAMERA_CtxInit(dev);
    if (EI_SUCCESS != s32Ret) {
        return EI_FAILURE;
    }

    SNS_GET_CTX(dev, pstSnsState);

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsState->pstSnsAttr = &s_astSnsAttr[i];
            break;
        }
    }

    pstSnsState->enSnsType = enType;
    pstSnsState->Dev = dev;

    if (i >= ARRAY_SIZE(s_astSnsAttr)) {
        PRT_VISS_ERR("%s does not support this chn configuration", SNS_NAME);
        return EI_FAILURE;
    }

    s32Ret = CAMERA_I2cInit(dev);
    if (EI_SUCCESS != s32Ret) {
        return EI_FAILURE;
    }

    stSns.stSnsAttrInfo.eSensorId = SNS_ID;
    stSns.stSnsAttrInfo.enDevType = DEV_TYPE;
    stSns.stSnsAttrInfo.pstSns = pstSnsState;

    s32Ret  = CAMERA_InitSensorExpFunction(&stSns.stSnsAttrInfo.stSnsExp);
    s32Ret |= VISS_SensorRegCallBack(dev, &stSns);
    if (EI_SUCCESS != s32Ret) {
        PRT_VISS_ERR("%s sensor register callback function failed!\n", SNS_NAME);
        return s32Ret;
    }

    s32Ret = CAMERA_OpenI2c(pstSnsState);
    CAMERA_CHECK_SUCCESS(s32Ret);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_UnregisterVissCallback(VISS_DEV dev)
{
    EI_S32 s32Ret;
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);

    s32Ret = CAMERA_ExitI2c(pstSnsState);
    CAMERA_CHECK_SUCCESS(s32Ret);

    s32Ret = VISS_SensorUnRegCallBack(dev, SNS_ID);
    if (EI_SUCCESS != s32Ret) {
        PRT_VISS_ERR("%s sensor unregister callback function failed!\n", SNS_NAME);
        return s32Ret;
    }

    CAMERA_CtxExit(dev);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_RegisterIspCallback(VISS_DEV Dev, ISP_DEV dev, ISP_3ALIB_S *pstAeLib, ISP_3ALIB_S *pstAwbLib)
{
    EI_S32 s32Ret;
    AE_SENSOR_REGISTER_S  stAeRegister;
    AWB_SENSOR_REGISTER_S stAwbRegister;

    CAMERA_CHECK_POINTER(pstAeLib);
    CAMERA_CHECK_POINTER(pstAwbLib);

    SNS_SET_ISP_TO_VISS(dev, Dev);

    stAeRegister.SnsId = SNS_ID;
    stAwbRegister.SnsId = SNS_ID;

    s32Ret  = CAMERA_InitAeExpFunction(&stAeRegister.stSnsExp);
    s32Ret |= EI_MI_AE_SensorRegCallBack(dev, pstAeLib, &stAeRegister);

    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s register callback function to ae lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    s32Ret  = CAMERA_InitAwbExpFunction(&stAwbRegister.stSnsExp);
    s32Ret |= EI_MI_AWB_SensorRegCallBack(dev, pstAwbLib, &stAwbRegister);

    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s register callback function to awb lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    return EI_SUCCESS;
}

static EI_S32 CAMERA_UnregisterIspCallback(ISP_DEV dev, ISP_3ALIB_S *pstAeLib, ISP_3ALIB_S *pstAwbLib)
{
    EI_S32 s32Ret;

    CAMERA_CHECK_POINTER(pstAeLib);
    CAMERA_CHECK_POINTER(pstAwbLib);

    s32Ret = EI_MI_AE_SensorUnRegCallBack(dev, pstAeLib, SNS_ID);
    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s unregister callback function to ae lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    s32Ret = EI_MI_AWB_SensorUnRegCallBack(dev, pstAwbLib, SNS_ID);
    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s unregister callback function to awb lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    return EI_SUCCESS;
}

static EI_S32 CAMERA_GetVissDevAttrBySns(SNS_TYPE_E enType,
    VISS_DEV_ATTR_S *pstVissDevAttr)
{
    EI_U32 i;
    const SNS_TYPE_ATTR_S *pstSnsType;

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsType = &s_astSnsAttr[i];
            pstVissDevAttr->stSize          = pstSnsType->stSize;
            pstVissDevAttr->enWorkMode      = pstSnsType->enWorkMode;
            pstVissDevAttr->mClock          = pstSnsType->u32Mclock;
            pstVissDevAttr->enPixelFormat   = pstSnsType->enPixelFormat;
            pstVissDevAttr->enWdrMode       = pstSnsType->enWdrMode;
            pstVissDevAttr->enIspWdrMode    = pstSnsType->enIspWdrMode;
            pstVissDevAttr->enRgbSeq        = pstSnsType->enRgbSeq;
            pstVissDevAttr->u32ModuleClk    = pstSnsType->u32ModuleClk;
            pstVissDevAttr->u32Fps          = pstSnsType->u32FrameRate;
            pstVissDevAttr->u32IspClk       = pstSnsType->u32IspClk;
            pstVissDevAttr->u32IppuClk      = pstSnsType->u32IppuClk;
            pstVissDevAttr->pcSnsName       = SNS_NAME;
            pstVissDevAttr->stDevCfg        = pstSnsType->stDevCfg;
            return EI_SUCCESS;
        }
    }

    PRT_VISS_ERR("%s does not support this dev configuration", SNS_NAME);

    return EI_FAILURE;
}

static EI_S32 CAMERA_GetVissChnAttrBySns(SNS_TYPE_E enType,
    VISS_CHN_ATTR_S *pstVissChnAttr)
{
    EI_U32 i;
    const SNS_TYPE_ATTR_S *pstSnsType;

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsType = &s_astSnsAttr[i];
            pstVissChnAttr->stSize          = pstSnsType->stSize;
            pstVissChnAttr->enPixelFormat   = pstSnsType->enPixelFormat;
            pstVissChnAttr->stFrameRate.s32SrcFrameRate     = pstSnsType->u32FrameRate;
            return EI_SUCCESS;
        }
    }

    PRT_VISS_ERR("%s does not support this chn configuration", SNS_NAME);

    return EI_FAILURE;

}

CAMERA_OBJ_S stCameraSc200aimipiObj = {
    .pfnRegisterVissCallback    = CAMERA_RegisterVissCallback,
    .pfnUnRegisterVissCallback  = CAMERA_UnregisterVissCallback,
    .pfnRegisterIspCallback     = CAMERA_RegisterIspCallback,
    .pfnUnRegisterIspCallback   = CAMERA_UnregisterIspCallback,
    .pfnGetVissDevAttrBySns     = CAMERA_GetVissDevAttrBySns,
    .pfnGetVissChnAttrBySns     = CAMERA_GetVissChnAttrBySns,
};


#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

